"""
学生信息管理系统 - 服务层 (业务逻辑层)

📚 教学目标：
1. 理解分层架构的重要性
2. 学习业务逻辑与数据访问的分离
3. 掌握异常处理和错误管理
4. 了解模块间依赖关系的设计

🎯 本模块在项目中的作用：
- 处理复杂的业务逻辑
- 协调数据访问层和表示层
- 提供统一的错误处理
- 实现数据验证和业务规则

⭐ 学习顺序：【第3步】- 在学习完student.py和database.py后学习此模块

🔗 模块依赖关系：
- 依赖项：database.py (数据访问)、student.py (数据模型)
- 被依赖：main.py (表示层) 依赖此模块

💡 设计原则：
- 关注点分离：业务逻辑与数据访问分离
- 错误处理：统一的错误处理和返回格式
- 接口设计：为上层提供简洁易用的API
- 事务管理：确保数据操作的完整性

🎓 重点概念：
- 三层架构：表示层 -> 业务逻辑层 -> 数据访问层
- 依赖注入：通过构造函数注入数据库对象
- 错误传播：将底层错误转换为业务错误
- 返回值设计：统一的成功/失败返回格式
"""

from database import StudentDatabase  # 💡 导入数据访问层
from student import Student  # 💡 导入数据模型


class StudentService:
    """
    学生信息服务类 - 业务逻辑处理
    
    🎓 教学要点：
    - 服务层的职责：处理业务逻辑，协调各个组件
    - 依赖注入：通过构造函数获取依赖的对象
    - 接口设计：为上层提供统一、简洁的API
    - 错误处理：将技术错误转换为业务友好的错误信息
    
    💡 设计模式：
    - 门面模式(Facade)：为复杂的数据操作提供简单接口
    - 适配器模式：适配数据库操作和业务需求
    """

    def __init__(self):
        """
        初始化学生服务
        
        🎓 教学要点：
        - 依赖管理：创建和管理依赖的对象
        - 组合关系：StudentService包含StudentDatabase
        - 职责分工：服务层负责创建数据访问层对象
        
        💡 设计考虑：
        - 简单的依赖管理，适合小型项目
        - 如果项目复杂，可以考虑依赖注入框架
        """
        self.db = StudentDatabase()  # 💡 创建数据库访问对象

    def add_student(self, student):
        """
        添加学生信息
        
        🎓 教学要点：
        - 基本数据库操作：INSERT语句的使用
        - 参数化查询：防止SQL注入的最佳实践
        - 事务管理：commit()确保数据持久化
        - 资源管理：确保数据库连接被正确关闭
        
        💡 业务逻辑：
        1. 直接进行数据库操作，插入学生信息
        2. 提交事务确保数据保存
        3. 正确关闭数据库连接
        
        🔍 SQL注入防护：
        - 使用参数化查询 (?, ?, ?, ...)
        - 永远不要直接拼接SQL字符串
        
        :param student: Student对象，包含要添加的学生信息
        :return: (success: bool, messages: list) 
                success为True表示成功，False表示失败
                messages包含成功/失败的详细信息
        """
        conn = self.db.get_connection()
        cursor = conn.cursor()

        # 使用参数化查询插入学生信息
        cursor.execute('''
                       INSERT INTO students (student_id, name, age, gender, major, class_name, phone, email)
                       VALUES (?, ?, ?, ?, ?, ?, ?, ?)
                       ''', (student.student_id, student.name, student.age, student.gender,
                             student.major, student.class_name, student.phone, student.email))

        conn.commit()  # 提交事务，确保数据被保存
        self.db.close_connection(conn)  # 关闭数据库连接

        return True, ["学生信息添加成功！"]

    def get_student_by_id(self, student_id):
        """
        根据学号查询学生信息
        
        🎓 教学要点：
        - 精确查询：使用等号(=)进行精确匹配
        - 单条记录查询：使用fetchone()获取单条记录
        - 对象转换：将数据库记录转换为业务对象
        
        💡 查询模式：
        - 主键查询：通过唯一标识符快速定位记录
        - 单条记录：使用fetchone()获取单条记录
        - 类型转换：使用Student.from_tuple()转换数据格式
        
        :param student_id: 学号(字符串)
        :return: Student对象或None(未找到时)
        """
        conn = self.db.get_connection()
        cursor = conn.cursor()

        # 使用参数化查询查找特定学号的学生
        cursor.execute('SELECT * FROM students WHERE student_id = ?', (student_id,))
        result = cursor.fetchone()  # 获取单条记录

        if result:  # 检查是否找到记录
            student = Student.from_tuple(result)  # 转换为Student对象
            self.db.close_connection(conn)
            return student

        self.db.close_connection(conn)
        return None  # 未找到时返回None

    def get_students_by_name(self, name):
        """
        根据姓名查询学生信息（支持模糊查询）
        
        🎓 教学要点：
        - 模糊查询：使用LIKE操作符和通配符(%)
        - 批量查询：使用fetchall()获取多条记录
        - 列表操作：处理查询结果列表
        
        💡 SQL模糊查询：
        - LIKE操作符：用于模式匹配
        - %通配符：匹配任意长度的字符
        - f'%{name}%'：姓名可以出现在任意位置
        
        :param name: 姓名或姓名的一部分
        :return: Student对象列表，可能为空列表
        """
        conn = self.db.get_connection()
        cursor = conn.cursor()

        # 使用LIKE进行模糊查询，%{name}%表示name可以出现在任意位置
        cursor.execute('SELECT * FROM students WHERE name LIKE ?', (f'%{name}%',))
        results = cursor.fetchall()  # 获取所有匹配的记录

        students = []  # 创建结果列表
        for result in results:  # 遍历查询结果
            student = Student.from_tuple(result)  # 转换为Student对象
            if student:  # 只添加成功转换的对象
                students.append(student)

        self.db.close_connection(conn)
        return students  # 返回Student对象列表

    def get_all_students(self):
        """获取所有学生信息"""
        conn = self.db.get_connection()
        cursor = conn.cursor()
        cursor.execute('SELECT * FROM students ORDER BY student_id')
        results = cursor.fetchall()

        students = []
        for result in results:
            student = Student.from_tuple(result)
            if student:
                students.append(student)

        self.db.close_connection(conn)
        return students

    def update_student(self, student_id, updated_student):
        """
        更新学生信息
        🎓 教学要点：
        - 更新操作：使用UPDATE语句更新记录
        - 参数化查询：安全的SQL操作
        - 事务管理：确保数据一致性
        :param student_id: 学号(字符串)
        :param updated_student: Student对象，包含更新后的学生信息
        :return: (success: bool, message: str)
                success为True表示成功，False表示失败
                message包含成功/失败的详细信息
        """
        # 检查学生是否存在
        existing_student = self.get_student_by_id(student_id)
        if not existing_student:
            return False, [f"学号 {student_id} 不存在！"]

        conn = self.db.get_connection()
        cursor = conn.cursor()
        cursor.execute('''
                       UPDATE students
                       SET student_id = ?,
                           name       = ?,
                           age        = ?,
                           gender     = ?,
                           major      = ?,
                           class_name = ?,
                           phone      = ?,
                           email      = ?
                       WHERE student_id = ?
                       ''', (updated_student.student_id, updated_student.name, updated_student.age,
                             updated_student.gender, updated_student.major, updated_student.class_name,
                             updated_student.phone, updated_student.email, student_id))

        if cursor.rowcount > 0:
            conn.commit()
            self.db.close_connection(conn)
            return True, ["学生信息更新成功！"]
        else:
            self.db.close_connection(conn)
            return False, ["更新失败，学生不存在！"]

    def delete_student(self, student_id):
        """
        删除学生信息
        🎓 教学要点：
        - 删除操作：使用DELETE语句删除记录
        - 事务管理：确保删除操作的原子性
        - 参数化查询：安全的SQL操作
        :param student_id: 学号(字符串)
        :return: (success: bool, message: str)
                success为True表示成功，False表示失败
                message包含成功/失败的详细信息
        """
        # 检查学生是否存在
        existing_student = self.get_student_by_id(student_id)
        if not existing_student:
            return False, f"学号 {student_id} 不存在！"

        conn = self.db.get_connection()
        cursor = conn.cursor()
        cursor.execute('DELETE FROM students WHERE student_id = ?', (student_id,))

        if cursor.rowcount > 0:
            conn.commit()
            self.db.close_connection(conn)
            return True, "学生信息删除成功！"
        else:
            self.db.close_connection(conn)
            return False, "删除失败，学生不存在！"

    def get_statistics(self):
        """
        获取统计信息
        🎓 教学要点：
        - 数据统计：计算总学生数、按性别和专业分组统计
        - SQL聚合函数：使用COUNT()进行计数
        - 分组查询：使用GROUP BY进行分组统计
        - 返回格式：统一的统计信息字典
        💡 设计考虑：
        - 统计信息应简洁明了，便于上层使用
        - 统计结果可以用于生成报表或图表
        - 适用于数据分析和决策支持
        :return: 统计信息字典
        {
            'total_count': int,          # 总学生数
            'gender_stats': dict,      # 按性别统计 {'男': count, '女': count}
            'major_stats': dict        # 按专业统计 {'计算机应用技术': count, ...}
        }
        """
        conn = self.db.get_connection()
        cursor = conn.cursor()

        # 总学生数
        cursor.execute('SELECT COUNT(*) FROM students')
        total_count = cursor.fetchone()[0]

        # 按性别统计
        cursor.execute('SELECT gender, COUNT(*) FROM students GROUP BY gender')
        gender_stats = cursor.fetchall()

        # 按专业统计
        cursor.execute('SELECT major, COUNT(*) FROM students GROUP BY major')
        major_stats = cursor.fetchall()

        self.db.close_connection(conn)

        return {
            'total_count': total_count,
            'gender_stats': dict(gender_stats),
            'major_stats': dict(major_stats)
        }

if __name__ == "__main__":
    # 测试代码
    service = StudentService()
    print("学生服务初始化成功！")

    # 添加测试学生
    test_student = Student("2025221", "张三", 20, "男", "计算机应用技术", "计算机1班")
    success, messages = service.add_student(test_student)
    print(messages[0] if success else f"添加失败: {messages[0]}")

    # 查询测试学生
    student = service.get_student_by_id("2025221")
    print(student) if student else print("未找到学生信息")

    student_name = service.get_students_by_name('张三')
    if student_name:
        for s in student_name:
            print(s)
    else:
        print("未找到相关学生信息")
    print(f"查询到 {len(student_name)} 个学生：")

    # 更新测试学生
    updated_student = Student("2025221", "张三更新", 21, "男", "计算机科学", "计算机2班")
    success, message = service.update_student("2025221", updated_student)
    print(message)

    # 删除测试学生
    success, message = service.delete_student("2025221")
    print(message)
